#!/usr/bin/perl

=head1 NAME

Swignition::DataModel::Triple - A node that represents a triple.

=cut

package Swignition::DataModel::Triple;

use Carp;
use Swignition::DataModel::Node;

use constant TRUE      =>  1;
use constant FALSE     =>  0;
use strict;

our @ISA = ("Swignition::DataModel::Node");
our $VERSION = '0.1';

=head1 CONSTRUCTORS

=over

=item $node = Swignition::DataModel::Triple->new($model, $s, $p, $o)

Create a new triple. 

=cut

sub new
{
	my $class = shift;
	my $model = shift;
	my ($s, $p, $o) = (shift, shift, shift);
	
	confess ("Triples have three parts!")
		unless ( $s->isa('Swignition::DataModel::Node')
		&&       $p->isa('Swignition::DataModel::Node')
		&&       $o->isa('Swignition::DataModel::Node'));
	
	my $this = Swignition::DataModel::Node::new(__PACKAGE__, $model);
	
	$this->{'_'}->{'triple'} = {
			'subject' => $s,
			'predicate' => $p,
			'object' => $o
		};
	
	# Now that the triple has been created, notify each node of their
	# involvement.
	$s->add_usage('subject_of',    $this);
	$p->add_usage('predictate_of', $this);
	$o->add_usage('object_of',     $this);
	
	return $this;
}

=back

=head1 PUBLIC METHODS

C<Swignition::DataModel::Triple> also inherits from C<Swignition::DataModel::Node>.

=over

=item $node->subject

Get the subject of the triple.

=cut

sub subject
{
	my $this = shift;
	return $this->{'_'}->{'triple'}->{'subject'};
}

=item $node->predicate

Get the predicate of the triple.

=cut

sub predicate
{
	my $this = shift;
	return $this->{'_'}->{'triple'}->{'predicate'};
}

=item $node->object

Get the object of the triple.

=cut

sub object
{
	my $this = shift;
	return $this->{'_'}->{'triple'}->{'object'};
}

=item $node->triple_of

A list of graphs where this node is a triple.

=cut

sub triple_of
{
	my $this = shift;
	return $this->{'_'}->{'usage'}->{'triple_of'};
}

=item $node->rdf_compatible

Is the triple RDF-compatible. To be RDF-compatible, the triple must have
a resource or blank node as its subject; a resource as its predicate and
a resource, literal or blank node as its object.

(Note that Graphs and Triples are also allowed as subjects and objects
because each of them can be treated as blank nodes or resources using
reification.)

=cut

sub rdf_compatible
{
	my $this = shift;
	
	return FALSE unless ( $this->subject->isa('Swignition::DataModel::Resource')
	                   || $this->subject->isa('Swignition::DataModel::BlankNode') 
	                   || $this->subject->isa('Swignition::DataModel::Graph') 
	                   || $this->subject->isa('Swignition::DataModel::Triple') );

	return FALSE unless $this->predicate->isa('Swignition::DataModel::Resource');

	return FALSE unless ( $this->subject->isa('Swignition::DataModel::Resource')
	                   || $this->subject->isa('Swignition::DataModel::BlankNode') 
	                   || $this->subject->isa('Swignition::DataModel::Literal') 
	                   || $this->subject->isa('Swignition::DataModel::Graph') 
	                   || $this->subject->isa('Swignition::DataModel::Triple') );

	return TRUE;
}

=item $node->mergeable($an_other)

Returns true if (theoretically) this node can be merged with another node.

=cut

sub mergeable
{
	my $this = shift;
	my $that = shift;
	
	return FALSE unless $this->subject->same_as($that->subject);
	return FALSE unless $this->predicate->same_as($that->predicate);
	return FALSE unless $this->object->same_as($that->object);
	
	return TRUE;
}

=back

=cut

1;

